#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
script usage:

    python webhook.py [port]

request test:

    # http get request
    curl 'http://127.0.0.1:9981/shell/test.sh?d=life&o=master'
    curl 'http://127.0.0.1:9981/python/scripts/test.py?word=web&word=hook&limit=100&end='
    # http post request
    curl -d "" "http://127.0.0.1:9981/shell/test.sh"
"""
import os
import subprocess
import sys
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
from urlparse import urlparse, parse_qs


class MyHandler(BaseHTTPRequestHandler):

    ACTIONS = {
        'python': '/usr/bin/python',
        'shell': '/bin/sh',
    }

    def _set_headers(self):
        self.send_response(200)
        self.send_header('Content-type', 'text/html')
        self.end_headers()

    def _write(self, text):
        self.wfile.write(text)

    def do_GET(self):
        # print('do_GET: %s' % self.path)
        url = urlparse(self.path)

        path = url.path.strip('/')
        path = path.split('/') if len(path) > 0 else tuple()
        query = parse_qs(url.query)

        self._do(*path, **query)

    def do_POST(self):
        self.do_GET()

    def _do(self, *args, **kwargs):
        # print('_do: %s, %s' % (args, kwargs))
        if not args:
            # no action
            self.send_error(400, 'no action')
            return
        action = args[0]
        if not self.ACTIONS.has_key(action):
            # unsupport action
            self.send_error(400, 'unsupport action')
            return

        n = len(args)
        path = './'
        if (n > 1):
            for i in xrange(1, n):
                path = os.path.join(path, args[i])

        if not os.path.isfile(path):
            # only allow local script
            self.send_error(404, 'only allow local script')
            return

        self._do_action(self.ACTIONS[action], path, **kwargs)

    def _do_action(self, action, path, **kwargs):
        print('do %s: %s, %s' % (action, path, kwargs))
        args = [action, path]
        for k, v in kwargs.iteritems():
            n = len(v)
            if n <= 0: continue
            if n == 1:
                v = v[0]
            else:
                v = ','.join(v)
            # should split if args as list, otherwise option will have a
            # redundant whitespace before its head
            args.append('-' + k)
            args.append(v)
        self._call(args)

    def _call(self, args):
        command = ' '.join(args)
        print('>> ' + self.date_time_string())
        print('>> ' + command)
        retcode = subprocess.call(args)
        print('>> ret: %d' % retcode)

        self._set_headers()
        self._write(
            "<head>\n"
            "<title>Mission %(title)s</title>\n"
            "</head>\n"
            "<body>\n"
            "<h1>Mission %(title)s</h1>\n"
            "<p>cmd: %(cmd)s\n"
            "<p>ret: %(ret)d\n"
            "</body>\n" % {
                'title': 'Success' if retcode == 0 else 'Failed',
                'cmd': command,
                'ret': retcode,
            })

        # flush stdout after each call
        sys.stdout.flush()


def serve(port):
    try:
        server = HTTPServer(('localhost', port), MyHandler)
        sockname = server.socket.getsockname()
        print("serving at: http://%s:%d/" % (sockname[0], sockname[1]))
        server.serve_forever()
    except KeyboardInterrupt:
        print('^C received, shutting down server')
        server.socket.close()


if __name__ == "__main__":
    argv = sys.argv
    if len(argv) >= 2:
        try:
            port = int(argv[1])
        except ValueError:
            sys.exit('port %s must be numeric' % argv[1])
    else:
        port = 9981

    if not 1024 < port < 65535:
        sys.exit('port %d must between (1024, 65535)' % port)

    serve(port)
